/*******************************************************************************
 * File name:     timer.c
 * Description:   timer init functions
 * Project:       timer
 * Target:        LPC2478
 * Compiler:      arm-none-eabi-gcc
 * Date:          15-09-2011
 * Author:        Kuba
 * Based on:      ---
 ******************************************************************************/

/*==============================================================================
 Includes
==============================================================================*/
# include <stdbool.h>
# include <stddef.h>
# include "LPC24xx.h"
# include "hdr_scb.h"
# include "typedef.h"
# include "irq.h"
# include "board.h"

# include "timer.h"

/*==============================================================================
 Defines
==============================================================================*/
# define TIMERS      4
# define MATCH_NUM   4
# define CAP_NUM     2

/*==============================================================================
 Types
==============================================================================*/
struct timer {
   /* timer registers */
   volatile uint32 *ir;
   volatile uint32 *tcr;
   volatile uint32 *tc;
   volatile uint32 *pr;
   volatile uint32 *pc;
   volatile uint32 *mcr;
   volatile uint32 *mr0;
   volatile uint32 *mr1;
   volatile uint32 *mr2;
   volatile uint32 *mr3;
   volatile uint32 *ccr;
   volatile uint32 *cr0;
   volatile uint32 *cr1;
   volatile uint32 *emr;
   volatile uint32 *ctcr;
   /* values */
   uint32 mcrVal;
   uint32 mr0Val;
   uint32 mr1Val;
   uint32 mr2Val;
   uint32 mr3Val;
};

/*==============================================================================
 Globals
==============================================================================*/
/* array of pointers to user service functions */
void (*serviceArray[TIMERS][MATCH_NUM])(void);
/* timerArray has 4 timers */
struct timer timerArray[TIMERS];
/*==============================================================================
 Static ISR prototypes
==============================================================================*/
static void timer0Isr (void) __attribute__   ((interrupt("IRQ")));
static void timer1Isr (void) __attribute__   ((interrupt("IRQ")));
static void timer2Isr (void) __attribute__   ((interrupt("IRQ")));
static void timer3Isr (void) __attribute__   ((interrupt("IRQ")));

/*==============================================================================
 Static function prototypes
==============================================================================*/
static void dummyService (void);

/*==============================================================================
 Global function definitions
==============================================================================*/
/*------------------------------------------------------------------------------
 function name:   timerInit
 description:     timer initialization
 parameters:      pointer to timerConf struct
 returned value:  opaque pointer to timer struct
------------------------------------------------------------------------------*/
timer timerInit (struct timerConf *timerConf)
{
   timer tmr;

   serviceArray[0][0] = dummyService;     /* timer 0, match event 0 */
   serviceArray[0][1] = dummyService;     /* timer 0, match event 1 */
   serviceArray[0][2] = dummyService;     /* timer 0, match event 2 */
   serviceArray[0][3] = dummyService;     /* timer 0, match event 3 */

   serviceArray[1][0] = dummyService;     /* timer 1, match event 0 */
   serviceArray[1][1] = dummyService;     /* timer 1, match event 1 */
   serviceArray[1][2] = dummyService;     /* timer 1, match event 2 */
   serviceArray[1][3] = dummyService;     /* timer 1, match event 3 */

   serviceArray[2][0] = dummyService;     /* timer 0, match event 0 */
   serviceArray[2][1] = dummyService;     /* timer 0, match event 1 */
   serviceArray[2][2] = dummyService;     /* timer 0, match event 2 */
   serviceArray[2][3] = dummyService;     /* timer 0, match event 3 */

   serviceArray[3][0] = dummyService;     /* timer 0, match event 0 */
   serviceArray[3][1] = dummyService;     /* timer 0, match event 1 */
   serviceArray[3][2] = dummyService;     /* timer 0, match event 2 */
   serviceArray[3][3] = dummyService;     /* timer 0, match event 3 */

   switch (timerConf->number)
   {
   case timer0:
      /* set user functions */
      serviceArray[0][0] = timerConf->match[0].matchService;
      serviceArray[0][1] = timerConf->match[1].matchService;
      serviceArray[0][2] = timerConf->match[2].matchService;
      serviceArray[0][3] = timerConf->match[3].matchService;
      /* ADT init */
      tmr = &timerArray[0];
      tmr->ir     = (volatile uint32 *)&T0IR;
      tmr->tcr    = (volatile uint32 *)&T0TCR;
      tmr->tc     = (volatile uint32 *)&T0TC;
      tmr->pr     = (volatile uint32 *)&T0PR;
      tmr->pc     = (volatile uint32 *)&T0PC;
      tmr->mcr    = (volatile uint32 *)&T0MCR;
      tmr->mr0    = (volatile uint32 *)&T0MR0;
      tmr->mr1    = (volatile uint32 *)&T0MR1;
      tmr->mr2    = (volatile uint32 *)&T0MR2;
      tmr->mr3    = (volatile uint32 *)&T0MR3;
      tmr->ccr    = (volatile uint32 *)&T0CCR;
      tmr->cr0    = (volatile uint32 *)&T0CR0;
      tmr->cr1    = (volatile uint32 *)&T0CR1;
      tmr->emr    = (volatile uint32 *)&T0EMR;
      tmr->ctcr   = (volatile uint32 *)&T0CTCR;

      /* set MR0 */
      if (timerConf->match[0].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal = T_MCR_MR0I;
      }
      if (timerConf->match[0].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR0R;
      }
      if (timerConf->match[0].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR0S;
      }
      if (timerConf->match[0].delay)
      {
         tmr->mr0Val = timerConf->match[0].delay;
      }
      /* set MR1 */
      if (timerConf->match[1].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR1I;
      }
      if (timerConf->match[1].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR1R;
      }
      if (timerConf->match[1].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR1S;
      }
      if (timerConf->match[1].delay)
      {
         tmr->mr1Val = timerConf->match[1].delay;
      }
      /* set MR2 */
      if (timerConf->match[2].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR2I;
      }
      if (timerConf->match[2].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR2R;
      }
      if (timerConf->match[2].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR2S;
      }
      if (timerConf->match[2].delay)
      {
         tmr->mr2Val = timerConf->match[2].delay;
      }
      /* set MR3 */
      if (timerConf->match[3].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR3I;
      }
      if (timerConf->match[3].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR3R;
      }
      if (timerConf->match[3].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR3S;
      }
      if (timerConf->match[3].delay)
      {
         tmr->mr3Val = timerConf->match[3].delay;
      }

      /* hardware init */
      PCONP |= PCONP_PCTIM0;                          /* timer 0 is enabled on reset, just in case */
      switch (timerConf->pclk)                        /* set timer's PCLK */
      {
      case timerPCLK_CORE_FREQ:
         /* do nothing */
         break;

      case timerPCLK_CORE_FREQ_DIV2:
         PCLKSEL0 &= ~(PCLKSEL0_TIMER0_FREQ_DIV8);    /* this clears timer 0 bits */
         PCLKSEL0 |= PCLKSEL0_TIMER0_FREQ_DIV2;       /* set required PCLK */
         break;

      case timerPCLK_CORE_FREQ_DIV4:
         PCLKSEL0 &= ~(PCLKSEL0_TIMER0_FREQ_DIV8);
         PCLKSEL0 |= PCLKSEL0_TIMER0_FREQ_DIV4;
         break;

      case timerPCLK_CORE_FREQ_DIV8:
         PCLKSEL0 |= PCLKSEL0_TIMER0_FREQ_DIV8;       /* no need to clear bits  as there are 11 */
         break;

      default:
         return (FALSE);
      }
      /* clear all interrupts */
      T0IR = (T_IR_MR0_INTRPT | T_IR_MR1_INTRPT | T_IR_MR2_INTRPT | T_IR_MR3_INTRPT
               | T_IR_CR0_INTRPT | T_IR_CR1_INTRPT | T_IR_CR2_INTRPT | T_IR_CR3_INTRPT);
      /* reset timer before initialization */
      T0TCR    = T_TCR_CNT_RESET;

      if ((irqInit(irqTIMER0, (void *)timer0Isr, timerConf->priority)) == FALSE)
      {
         return (tmr = (timer)NULL);                  /* fatal error */
      }

      break;   /* end of tmr0- break just in case */


   case timer1:
      serviceArray[1][0] = timerConf->match[0].matchService;   /* set user function to the service array */
      serviceArray[1][1] = timerConf->match[1].matchService;
      serviceArray[1][2] = timerConf->match[2].matchService;
      serviceArray[1][3] = timerConf->match[3].matchService;

      tmr = &timerArray[1];                                    /* init private struct */
      tmr->ir     = (volatile uint32 *)&T1IR;
      tmr->tcr    = (volatile uint32 *)&T1TCR;
      tmr->tc     = (volatile uint32 *)&T1TC;
      tmr->pr     = (volatile uint32 *)&T1PR;
      tmr->pc     = (volatile uint32 *)&T1PC;
      tmr->mcr    = (volatile uint32 *)&T1MCR;
      tmr->mr0    = (volatile uint32 *)&T1MR0;
      tmr->mr1    = (volatile uint32 *)&T1MR1;
      tmr->mr2    = (volatile uint32 *)&T1MR2;
      tmr->mr3    = (volatile uint32 *)&T1MR3;
      tmr->ccr    = (volatile uint32 *)&T1CCR;
      tmr->cr0    = (volatile uint32 *)&T1CR0;
      tmr->cr1    = (volatile uint32 *)&T1CR1;
      tmr->emr    = (volatile uint32 *)&T1EMR;
      tmr->ctcr   = (volatile uint32 *)&T1CTCR;

      /* set MR0 */
      if (timerConf->match[0].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal = T_MCR_MR0I;
      }
      if (timerConf->match[0].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR0R;
      }
      if (timerConf->match[0].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR0S;
      }
      if (timerConf->match[0].delay)
      {
         tmr->mr0Val = timerConf->match[0].delay;
      }
      /* set MR1 */
      if (timerConf->match[1].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR1I;
      }
      if (timerConf->match[1].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR1R;
      }
      if (timerConf->match[1].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR1S;
      }
      if (timerConf->match[1].delay)
      {
         tmr->mr1Val = timerConf->match[1].delay;
      }
      /* set MR2 */
      if (timerConf->match[2].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR2I;
      }
      if (timerConf->match[2].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR2R;
      }
      if (timerConf->match[2].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR2S;
      }
      if (timerConf->match[2].delay)
      {
         tmr->mr2Val = timerConf->match[2].delay;
      }
      /* set MR3 */
      if (timerConf->match[3].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR3I;
      }
      if (timerConf->match[3].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR3R;
      }
      if (timerConf->match[3].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR3S;
      }
      if (timerConf->match[3].delay)
      {
         tmr->mr3Val = timerConf->match[3].delay;
      }

      PCONP |= PCONP_PCTIM1;                          /* timer 0 is enabled on reset */
      switch (timerConf->pclk)                        /* set timer's PCLK */
      {
      case timerPCLK_CORE_FREQ:
         /* do nothing */
         break;

      case timerPCLK_CORE_FREQ_DIV2:
         PCLKSEL0 &= ~(PCLKSEL0_TIMER1_FREQ_DIV8);    /* this clears timer 0 bits */
         PCLKSEL0 |= PCLKSEL0_TIMER1_FREQ_DIV2;       /* set required PCLK */
         break;

      case timerPCLK_CORE_FREQ_DIV4:
         PCLKSEL0 &= ~(PCLKSEL0_TIMER1_FREQ_DIV8);
         PCLKSEL0 |= PCLKSEL0_TIMER1_FREQ_DIV4;
         break;

      case timerPCLK_CORE_FREQ_DIV8:
         PCLKSEL0 |= PCLKSEL0_TIMER1_FREQ_DIV8;       /* no need to clear bits  as there are 11 */
         break;

      default:
         return (FALSE);
      }

      /* clear all interrupts */
      T1IR = (T_IR_MR0_INTRPT | T_IR_MR1_INTRPT | T_IR_MR2_INTRPT | T_IR_MR3_INTRPT
               | T_IR_CR0_INTRPT | T_IR_CR1_INTRPT | T_IR_CR2_INTRPT | T_IR_CR3_INTRPT);
      /* reset timer before initialization */
      T1TCR    = T_TCR_CNT_RESET;

      if ((irqInit(irqTIMER1, (void *)timer1Isr, timerConf->priority)) == FALSE)
      {
         return (tmr = (timer)NULL);               /* fatal error */
      }
      break;   /* end of tmr1 */


   case timer2:
      serviceArray[2][0] = timerConf->match[0].matchService; /* set user function to the service array */
      serviceArray[2][1] = timerConf->match[1].matchService;
      serviceArray[2][2] = timerConf->match[2].matchService;
      serviceArray[2][3] = timerConf->match[3].matchService;

      tmr = &timerArray[2];                                    /* init private struct */
      tmr->ir     = (volatile uint32 *)&T2IR;
      tmr->tcr    = (volatile uint32 *)&T2TCR;
      tmr->tc     = (volatile uint32 *)&T2TC;
      tmr->pr     = (volatile uint32 *)&T2PR;
      tmr->pc     = (volatile uint32 *)&T2PC;
      tmr->mcr    = (volatile uint32 *)&T2MCR;
      tmr->mr0    = (volatile uint32 *)&T2MR0;
      tmr->mr1    = (volatile uint32 *)&T2MR1;
      tmr->mr2    = (volatile uint32 *)&T2MR2;
      tmr->mr3    = (volatile uint32 *)&T2MR3;
      tmr->ccr    = (volatile uint32 *)&T2CCR;
      tmr->cr0    = (volatile uint32 *)&T2CR0;
      tmr->cr1    = (volatile uint32 *)&T2CR1;
      tmr->emr    = (volatile uint32 *)&T2EMR;
      tmr->ctcr   = (volatile uint32 *)&T2CTCR;

      /* set MR0 */
      if (timerConf->match[0].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal = T_MCR_MR0I;
      }
      if (timerConf->match[0].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR0R;
      }
      if (timerConf->match[0].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR0S;
      }
      if (timerConf->match[0].delay)
      {
         tmr->mr0Val = timerConf->match[0].delay;
      }
      /* set MR1 */
      if (timerConf->match[1].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR1I;
      }
      if (timerConf->match[1].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR1R;
      }
      if (timerConf->match[1].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR1S;
      }
      if (timerConf->match[1].delay)
      {
         tmr->mr1Val = timerConf->match[1].delay;
      }
      /* set MR2 */
      if (timerConf->match[2].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR2I;
      }
      if (timerConf->match[2].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR2R;
      }
      if (timerConf->match[2].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR2S;
      }
      if (timerConf->match[2].delay)
      {
         tmr->mr2Val = timerConf->match[2].delay;
      }
      /* set MR3 */
      if (timerConf->match[3].interrupt == matchINTERRUPT_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR3I;
      }
      if (timerConf->match[3].reset == matchRESET_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR3R;
      }
      if (timerConf->match[3].stop == matchSTOP_ENABLE)
      {
         tmr->mcrVal |= T_MCR_MR3S;
      }
      if (timerConf->match[3].delay)
      {
         tmr->mr3Val = timerConf->match[3].delay;
      }

      PCONP |= PCONP_PCTIM2;                             /* timer2 on */
      switch (timerConf->pclk)                           /* set timer's PCLK */
      {
      case timerPCLK_CORE_FREQ:
         /* do nothing */
         break;

      case timerPCLK_CORE_FREQ_DIV2:
         PCLKSEL1 &= ~(PCLKSEL1_TIMER2_FREQ_DIV8);    /* this clears timer 0 bits */
         PCLKSEL1 |= PCLKSEL1_TIMER2_FREQ_DIV2;       /* set required PCLK */
         break;

      case timerPCLK_CORE_FREQ_DIV4:
         PCLKSEL1 &= ~(PCLKSEL1_TIMER2_FREQ_DIV8);
         PCLKSEL1 |= PCLKSEL1_TIMER2_FREQ_DIV4;
         break;

      case timerPCLK_CORE_FREQ_DIV8:
         PCLKSEL1 |= PCLKSEL1_TIMER2_FREQ_DIV8;       /* no need to clear bits  as there are 11 */
         break;

      default:
         return (FALSE);
      }

      /* clear all interrupts */
      T2IR = (T_IR_MR0_INTRPT | T_IR_MR1_INTRPT | T_IR_MR2_INTRPT | T_IR_MR3_INTRPT
               | T_IR_CR0_INTRPT | T_IR_CR1_INTRPT | T_IR_CR2_INTRPT | T_IR_CR3_INTRPT);
      /* reset timer before initialization */
      T2TCR    = T_TCR_CNT_RESET;

      if ((irqInit(irqTIMER2, (void *)timer2Isr, timerConf->priority)) == FALSE)
      {
         return (tmr = (timer)NULL);         /* fatal error */
      }
      break;   /* end of tmr2 */


   case timer3:
      serviceArray[3][0] = timerConf->match[0].matchService; /* set user function to the service array */
      serviceArray[3][1] = timerConf->match[1].matchService;
      serviceArray[3][2] = timerConf->match[2].matchService;
      serviceArray[3][3] = timerConf->match[3].matchService;

      tmr = &timerArray[3];                                    /* init private struct */
      tmr->ir     = (volatile uint32 *)&T3IR;
      tmr->tcr    = (volatile uint32 *)&T3TCR;
      tmr->tc     = (volatile uint32 *)&T3TC;
      tmr->pr     = (volatile uint32 *)&T3PR;
      tmr->pc     = (volatile uint32 *)&T3PC;
      tmr->mcr    = (volatile uint32 *)&T3MCR;
      tmr->mr0    = (volatile uint32 *)&T3MR0;
      tmr->mr1    = (volatile uint32 *)&T3MR1;
      tmr->mr2    = (volatile uint32 *)&T3MR2;
      tmr->mr3    = (volatile uint32 *)&T3MR3;
      tmr->ccr    = (volatile uint32 *)&T3CCR;
      tmr->cr0    = (volatile uint32 *)&T3CR0;
      tmr->cr1    = (volatile uint32 *)&T3CR1;
      tmr->emr    = (volatile uint32 *)&T3EMR;
      tmr->ctcr   = (volatile uint32 *)&T3CTCR;

      /* set MR0 */
       if (timerConf->match[0].interrupt == matchINTERRUPT_ENABLE)
       {
          tmr->mcrVal = T_MCR_MR0I;
       }
       if (timerConf->match[0].reset == matchRESET_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR0R;
       }
       if (timerConf->match[0].stop == matchSTOP_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR0S;
       }
       if (timerConf->match[0].delay)
       {
          tmr->mr0Val = timerConf->match[0].delay;
       }
       /* set MR1 */
       if (timerConf->match[1].interrupt == matchINTERRUPT_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR1I;
       }
       if (timerConf->match[1].reset == matchRESET_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR1R;
       }
       if (timerConf->match[1].stop == matchSTOP_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR1S;
       }
       if (timerConf->match[1].delay)
       {
          tmr->mr1Val = timerConf->match[1].delay;
       }
       /* set MR2 */
       if (timerConf->match[2].interrupt == matchINTERRUPT_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR2I;
       }
       if (timerConf->match[2].reset == matchRESET_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR2R;
       }
       if (timerConf->match[2].stop == matchSTOP_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR2S;
       }
       if (timerConf->match[2].delay)
       {
          tmr->mr2Val = timerConf->match[2].delay;
       }
       /* set MR3 */
       if (timerConf->match[3].interrupt == matchINTERRUPT_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR3I;
       }
       if (timerConf->match[3].reset == matchRESET_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR3R;
       }
       if (timerConf->match[3].stop == matchSTOP_ENABLE)
       {
          tmr->mcrVal |= T_MCR_MR3S;
       }
       if (timerConf->match[3].delay)
       {
          tmr->mr3Val = timerConf->match[3].delay;
       }

      PCONP |= PCONP_PCTIM3;
      switch (timerConf->pclk)                               /* set timer's PCLK */
      {
      case timerPCLK_CORE_FREQ:
         /* do nothing */
         break;

      case timerPCLK_CORE_FREQ_DIV2:
         PCLKSEL1 &= ~(PCLKSEL1_TIMER3_FREQ_DIV8);    /* this clears timer 0 bits */
         PCLKSEL1 |= PCLKSEL1_TIMER3_FREQ_DIV2;       /* set required PCLK */
         break;

      case timerPCLK_CORE_FREQ_DIV4:
         PCLKSEL1 &= ~(PCLKSEL1_TIMER3_FREQ_DIV8);
         PCLKSEL1 |= PCLKSEL1_TIMER3_FREQ_DIV4;
         break;

      case timerPCLK_CORE_FREQ_DIV8:
         PCLKSEL1 |= PCLKSEL1_TIMER3_FREQ_DIV8;       /* no need to clear bits  as there are 11 */
         break;

      default:
         return (FALSE);
      }
      /* clear all interrupts */
      T3IR = (T_IR_MR0_INTRPT | T_IR_MR1_INTRPT | T_IR_MR2_INTRPT | T_IR_MR3_INTRPT
               | T_IR_CR0_INTRPT | T_IR_CR1_INTRPT | T_IR_CR2_INTRPT | T_IR_CR3_INTRPT);
      /* reset timer before initialization */
      T3TCR    = T_TCR_CNT_RESET;

      if ((irqInit(irqTIMER3, (void *)timer3Isr, timerConf->priority)) == FALSE)
      {
         return (tmr = (timer)NULL);         /* fatal error */
      }
      break;   /* end of tmr3 */


   default:
      return tmr = (timer)NULL;
   }

   return (tmr);
}

/*------------------------------------------------------------------------------
 function name:   timerMatchEnable
 description:     start match event
 parameters:      pointer to timer struct
 returned value:  none
------------------------------------------------------------------------------*/
void timerMatchEnable (timer tmr)
{
   *tmr->tcr = T_TCR_CNT_ENABLE;
   *tmr->mcr = tmr->mcrVal;
   *tmr->mr0 = tmr->mr0Val;
   *tmr->mr1 = tmr->mr1Val;
   *tmr->mr2 = tmr->mr2Val;
   *tmr->mr3 = tmr->mr3Val;
}

/*------------------------------------------------------------------------------
 function name:   timerGetPendingIntrpt
 description:     returns word that bits say which interrupt is pending:
                    0- MR0 interrupt flag for match channel 0
                    1- MR1 interrupt flag for match channel 1
                    2- MR2 interrupt flag for match channel 2
                    3- MR3 interrupt flag for match channel 3
                    4- CR0 interrupt flag for capture channel 0 event
                    5- CR1 interrupt flag for capture channel 1 event
                    6- CR2 interrupt flag for capture channel 2 event
                    7- CR3 interrupt flag for capture channel 3 event
 parameters:      none
 returned value:  uint8 word with pending interrupt bits
------------------------------------------------------------------------------*/


/*==============================================================================
 Static function definitions
==============================================================================*/

/*==============================================================================
 Static ISR definitions
==============================================================================*/
/*------------------------------------------------------------------------------
 function name:      timer0Isr
 description:     ISR for timer 0- it calls user service function
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
void timer0Isr (void)
{
   uint32 reg;

   reg = T0IR & 0xFF;            /* read interrupt register */

   switch (reg)                  /* we need to check only 8 bits */
   {
   case (T_IR_MR0_INTRPT):
      T0IR |= T_IR_MR0_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[0][0])();   /* call user service for timer 0, match event 0 */
      break;

   case (T_IR_MR1_INTRPT):
      T0IR |= T_IR_MR1_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[0][1])();   /* call user service for timer 0, match event 1 */
      break;

   case (T_IR_MR2_INTRPT):
      T0IR |= T_IR_MR2_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[0][2])();   /* call user service for timer 0, match event 2 */
      break;

   case (T_IR_MR3_INTRPT):
      T0IR |= T_IR_MR3_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[0][3])();   /* call user service for timer 0, match event 3 */
      break;

   default:
      /* clear all match interrupts */
      T0IR |= (T_IR_MR0_INTRPT | T_IR_MR1_INTRPT | T_IR_MR2_INTRPT | T_IR_MR3_INTRPT);
      break;
   }
   VICVectAddr = 0;
}

/*------------------------------------------------------------------------------
 function name:   timer1Isr
 description:     ISR for timer 1- it calls user service function
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
void timer1Isr (void)
{
   uint32 reg;

   reg = T1IR;                   /* read interrupt register */

   switch (reg & 0xFF)           /* we need to check only 8 bits */
   {
   case T_IR_MR0_INTRPT:
      T1IR |= T_IR_MR0_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[1][0])();   /* call user service for timer 0, match event 0 */
      break;

   case T_IR_MR1_INTRPT:
      T1IR |= T_IR_MR1_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[1][1])();   /* call user service for timer 0, match event 1 */
      break;

   case T_IR_MR2_INTRPT:
      T1IR |= T_IR_MR2_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[1][2])();   /* call user service for timer 0, match event 2 */
      break;

   case T_IR_MR3_INTRPT:
      T1IR |= T_IR_MR3_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[1][3])();   /* call user service for timer 0, match event 3 */
      break;

   default:
      /* clear all match interrupts */
      T1IR |= (T_IR_MR0_INTRPT | T_IR_MR1_INTRPT | T_IR_MR2_INTRPT | T_IR_MR3_INTRPT);
      break;
   }

   VICVectAddr = 0;
}

/*------------------------------------------------------------------------------
 function name:   timer2Isr
 description:     ISR for timer 2- it calls user service function
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
void timer2Isr (void)
{
   uint32 reg;

   reg = T2IR;                   /* read interrupt register */

   switch (reg & 0xFF)           /* we need to check only 8 bits */
   {
   case T_IR_MR0_INTRPT:
      T2IR |= T_IR_MR0_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[2][0])();   /* call user service for timer 0, match event 0 */
      break;

   case T_IR_MR1_INTRPT:
      T2IR |= T_IR_MR1_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[2][1])();   /* call user service for timer 0, match event 1 */
      break;

   case T_IR_MR2_INTRPT:
      T2IR |= T_IR_MR2_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[2][2])();   /* call user service for timer 0, match event 2 */
      break;

   case T_IR_MR3_INTRPT:
      T2IR |= T_IR_MR3_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[2][3])();   /* call user service for timer 0, match event 3 */
      break;

   default:
      /* clear all match interrupts */
      T2IR |= (T_IR_MR0_INTRPT | T_IR_MR1_INTRPT | T_IR_MR2_INTRPT | T_IR_MR3_INTRPT);
      break;
   }
   VICVectAddr = 0;
}

/*------------------------------------------------------------------------------
 function name:   timer2Isr
 description:     ISR for timer 2- it calls user service function
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
void timer3Isr (void)
{
   uint32 reg;

   reg = T3IR;                   /* read interrupt register */

   switch (reg & 0xFF)           /* we need to check only 8 bits */
   {
   case T_IR_MR0_INTRPT:
      T3IR |= T_IR_MR0_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[3][0])();   /* call user service for timer 0, match event 0 */
      break;

   case T_IR_MR1_INTRPT:
      T3IR |= T_IR_MR1_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[3][1])();   /* call user service for timer 0, match event 1 */
      break;

   case T_IR_MR2_INTRPT:
      T3IR |= T_IR_MR2_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[3][2])();   /* call user service for timer 0, match event 2 */
      break;

   case T_IR_MR3_INTRPT:
      T3IR |= T_IR_MR3_INTRPT;   /* reset the MR0 interrupt */
      (*serviceArray[3][3])();   /* call user service for timer 0, match event 3 */
      break;

   default:
      /* clear all match interrupts */
      T3IR |= (T_IR_MR0_INTRPT | T_IR_MR1_INTRPT | T_IR_MR2_INTRPT | T_IR_MR3_INTRPT);
      break;
   }

   VICVectAddr = 0;
}
/*------------------------------------------------------------------------------
 function name:   dummyService
 description:     does nothing
 parameters:      none
 returned value:  none
------------------------------------------------------------------------------*/
static void dummyService (void)
{
   return;
}
/******************************************************************************
* END OF FILE
******************************************************************************/


